//==============================================================================
// GetOption.cc
// ----------------------------------------------------------------------------
// See include file for description.
//
//
// K. James Durbin    
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//

#include "GetOption.hh"

//---------------------------------------------------
// * GetOption
//---------------------------------------------------
// Sets up the GetOption parser.   optDef defines the accepted options.  Options 
// that are followed by a : take a parameter, options without a : are assumed to 
// have no parameter.  
//
//
GetOption::GetOption(int argc,char **argv,const char* optDef)
{
  bool match,freeArgFound;
  mValid = true;
  vector <string> FreeArgs;

  mOptDef = optDef;

  // ? and h are always valid options....
  mOptDef = mOptDef+'h';
  mOptDef = mOptDef+'?';

  freeArgFound = false;

  // argNum = 0 is the name of the program
  for(int argNum = 1;argNum < argc;argNum++){
	 
    // A putative option is found
    if (argv[argNum][0] == '-'){
      match = false;
      //cout<<"option char="<<argv[argNum][0]<<"\n";
      // look at each option definition...
      for (int defNum = 0;defNum < mOptDef.size();defNum++){
		  // Found a match in the option definition so add it to list..
		  if (mOptDef[defNum] == argv[argNum][1]){
			 //cout<<"Option added to list: "<<mOptDef[defNum]<<"\n";
			 mOptions.push_back(mOptDef[defNum]);
			 match = true;
			 
			 // If the definition expects an argument
			 if (defNum < (mOptDef.size()-1)){
				if (mOptDef[defNum+1] == ':'){
				  // If the argument is any longer than a single 
				  // character, it is an error (for now).
				  if (argv[argNum][2] == 0){
					 // Verify that an argument and not a option follows, then 
					 // add it to the argument list..
					 if (argv[argNum+1][0] != '-'){
						mArgs.push_back(argv[argNum+1]);
						argNum++;
					 }else{
						mValid = false;
					 }
				  }else{		
					 mValid = false;
				  }
				}
			 }
			 // Only want to look for one option per pass
			 defNum = mOptDef.size();
		  }
      }
      if (!match) mValid = false;
    }else{
      // Free floating argument found. 
      FreeArgs.push_back(argv[argNum]);
    }
  }
  
  // Tack free arguments onto end of argument list.
  for(int i = 0;i< FreeArgs.size();i++){
    mArgs.push_back(FreeArgs[i]);
  }

  mOptIdx = 0;
  mArgIdx = 0;
}

//---------------------------------------------------
// * NextOption
//---------------------------------------------------
// Returns the next option from the command line.  
//
char
GetOption::NextOption()
{
  if (!mValid){
    mOptIdx = mOptions.size(); // force an exit.
    mValid = true;
    return('?');
  }

  if (mOptIdx < mOptions.size()){
	 mFormattedOptions+=mOptions[mOptIdx];
    return(mOptions[mOptIdx++]);
  }else{
    return(OPTION_EOF);
  }
}

//---------------------------------------------------
// * NextArg
//---------------------------------------------------
// Gets the next argument available from the command line.  Argument here means the 
// argument to an option.   -b 456   has an option, 'b', which is returned by 
// NextOption, and an argument, '456' which is returned by this function. 
// 
string
GetOption::NextArg()
{

  //cout<<"mValid="<<mValid<<"\n";
  //cout<<"mArgs.size()="<<mArgs.size()<<"\n";
  
  if (!mValid){
    mArgIdx = mOptions.size(); // force an exit.
    mValid = true;
    return("?");
  }

  if (mArgIdx < mArgs.size()){
	 mFormattedOptions+=mArgs[mArgIdx];
    return(mArgs[mArgIdx++]);
  }else{
    return("");
  }
}

//---------------------------------------------------
// * GetFreeArg
//---------------------------------------------------
// This function returns the next argument that is not associated with an 
// option.  The purpose is that you may have a command line that has a 
// series of options, and then a simple list of files.  This function can be 
// used to retrieve the simple list of files, one at a time.  
//
string
GetOption::GetFreeArg()
{
  if (!mValid){
    mArgIdx = mOptions.size(); // force an exit.
    mValid = true;
    return("?");
  }

  if (mArgIdx < mArgs.size()){
	 mFormattedOptions+=mArgs[mArgIdx];
    return(mArgs[mArgIdx++]);
  }else{
    return("");
  }
}





